package com.gcgo.zk;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

public class ServiceDiscovery {
    private String registryAddress; // 注册中心的地址

    private ConcurrentHashMap<String, String> serviceAddressMap;
    private ConcurrentHashMap<String, Long> serviceTimeMap;
    private ZkClient zk = null;
    private Integer num = 0;
    private String getOne = "";
    private String getTwo = "";

    public ServiceDiscovery(String registryAddress) {
        this.registryAddress = registryAddress;
        System.out.println(this.registryAddress);
        this.zk = connectServer();
        System.out.println(this.zk);
        for (; ; ) {
            if (zk != null) {
                break;
            }
        }
        watchNode();
        //查询对应的响应时间
        watchTime();
    }

    private void watchTime() {
        zk.subscribeChildChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME, (path, list) -> {
            /**
             *path:监听路径
             * list:当前变化后的children集合
             */
            System.out.println("服务节点发生了变化。。。正在更新响应时间。。");
            watchTime();
        });
        List<String> nodeTimeList = zk.getChildren(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME);
        ConcurrentHashMap<String, Long> dataMap = new ConcurrentHashMap<>();

        for (String node : nodeTimeList) {
            Long time = zk.readData(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME + "/" + node);
            dataMap.put(node, time);
            //监听响应时间的变化
            zk.subscribeDataChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME + "/" + node, new IZkDataListener() {
                @Override
                public void handleDataChange(String path, Object o) {
                    String[] split = path.split("/");
                    String nodeName = split[3];

                    //更新map就好了

                    if (serviceTimeMap.containsKey(nodeName)) {

                        System.out.println("路径：" + path + " 的响应时间发生了变化，正在更新");
                        serviceTimeMap.put(nodeName, (Long) o);
                        System.out.println("更新时间：" + o);
                        System.out.println("更新后的响应时间为：" + serviceTimeMap);
                    }

                }

                @Override
                public void handleDataDeleted(String path) {

                }
            });
        }
        this.serviceTimeMap = dataMap;
        System.out.println("初始化响应时间："+serviceTimeMap);
    }

    private void watchNode() {
        zk.subscribeChildChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN, (path, list) -> {
            /**
             *path:监听路径
             * list:当前变化后的children集合
             */
            System.out.println("服务节点发生了变化。。。正在更新。。");
            watchNode();
        });
        List<String> nodeList = zk.getChildren(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN);
        ConcurrentHashMap<String, String> dataMap = new ConcurrentHashMap<>();
        for (String node : nodeList) {
            String address = zk.readData(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN + "/" + node);
            dataMap.put(node, address);
        }
        System.out.println("获得服务节点：" + dataMap);
        this.serviceAddressMap = dataMap;
    }

    private ZkClient connectServer() {
        ZkClient zkClient = new ZkClient(registryAddress);
        System.out.println(zkClient);

        return new ZkClient(registryAddress);
    }

    public String discover() {
        String data = null;
        if (serviceAddressMap.size() == 1) {
            //只有一个服务器
            for (Map.Entry<String, String> entry : serviceAddressMap.entrySet()) {
                data = entry.getKey() + ":" + entry.getValue();//c000000012:127.0.0.1:8080
            }
        } else {
            //负载均衡：先比较时间
            System.out.println("当前各个服务器响应时间为："+serviceTimeMap);
            String address = null;
            long time = Long.MAX_VALUE;
            for (Map.Entry<String, Long> entry : serviceTimeMap.entrySet()) {
                long time1 = entry.getValue();
                if (time1 < time) {
                    time = time1;
                    address = entry.getKey();
                } else if (time1 == time) {
                    int i = ThreadLocalRandom.current().nextInt(2);
                    if (i == 1) {//随机选一个服务器
                        //time = time1;
                        address = entry.getKey();
                        System.out.println("响应时间相同，随机选择服务端");
                    }
                }
            }
            assert address != null;
            data = address + ":" + serviceAddressMap.get(address);
        }
        System.out.println("选择了服务提供方：" + data);
        return data;
    }

}
